package com.ruoyi.system.service.impl;

import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.FileEspVo;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.util.FileSystemUtils;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import java.io.IOException;
import java.nio.file.*;
import java.util.concurrent.*;
@Service
public class FileUploadService {

    // 临时存储上传状态 key: fileId, value: 已接收分块数
    private final Map<String, AtomicInteger> uploadProgress = new ConcurrentHashMap<>();
    private final Path tempDir = Paths.get("uploads/temp");
    private final Path finalDir = Paths.get(RuoYiConfig.getAvatarPath());

    public Boolean processChunk(FileEspVo fileEspVo) throws IOException {
        // 参数校验
        validateChunk(fileEspVo);

        // 解码Base64数据
        byte[] chunkBytes = Base64Utils.decodeFromString(fileEspVo.getChunkData());

        // 创建临时目录
        Path chunkDir = tempDir.resolve(fileEspVo.getFileId());
        Files.createDirectories(chunkDir);

        // 保存分块到临时文件
        Path chunkFile = chunkDir.resolve("chunk_" + fileEspVo.getChunkNumber());
        Files.write(chunkFile, chunkBytes);

        // 更新进度
        int received = uploadProgress.computeIfAbsent(
                fileEspVo.getFileId(),
                k -> new AtomicInteger(0)
        ).incrementAndGet();

        // 检查是否完成
        if (received == fileEspVo.getTotalChunks()) {
            mergeChunks(fileEspVo, chunkDir);
            return true;
        }
        return false;
    }






    private void validateChunk(FileEspVo fileEspVo) {
        if (fileEspVo.getChunkNumber() == null || fileEspVo.getTotalChunks() == null) {
            throw new IllegalArgumentException("分块信息不完整");
        }
        if (fileEspVo.getChunkNumber() < 1 || fileEspVo.getChunkNumber() > fileEspVo.getTotalChunks()) {
            throw new IllegalArgumentException("无效的分块序号");
        }
    }

    private void mergeChunks(FileEspVo fileEspVo, Path chunkDir) throws IOException {
        // 创建最终目录
        Files.createDirectories(finalDir);

        // 设置最终文件路径
        String finalFileName = System.currentTimeMillis() + "_" + fileEspVo.getFileName();
        Path outputFile = finalDir.resolve(finalFileName);
        fileEspVo.setFilePath(outputFile.toString());

        // 合并分块
        try (FileChannel outputChannel = FileChannel.open(outputFile,
                StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {

            for (int i = 1; i <= fileEspVo.getTotalChunks(); i++) {
                Path chunkFile = chunkDir.resolve("chunk_" + i);
                try (FileChannel inputChannel = FileChannel.open(chunkFile, StandardOpenOption.READ)) {
                    inputChannel.transferTo(0, inputChannel.size(), outputChannel);
                }
            }
        }

        System.out.println(outputFile);
        System.out.println(finalFileName);
        // 清理临时文件
        FileSystemUtils.deleteRecursively(chunkDir);
        uploadProgress.remove(fileEspVo.getFileId());
    }

    public int getReceivedChunks(String fileId) {
        return uploadProgress.getOrDefault(fileId, new AtomicInteger(0)).get();
    }






        // 线程池（实际项目建议通过配置类设置）
        private final ExecutorService executor = Executors.newFixedThreadPool(4);
        // 上传进度跟踪（线程安全）
        private final ConcurrentMap<String, AtomicInteger> uploadProgress1 = new ConcurrentHashMap<>();

        public CompletableFuture<AjaxResult> processChunk1(FileEspVo chunk) {
            return CompletableFuture.supplyAsync(() -> {
                try {
                    long startTime1 = System.currentTimeMillis();
                    // 1. 参数校验
                    if (chunk.getFileId() == null || chunk.getChunkData() == null) {
                        return AjaxResult.error("参数不完整");
                    }
                    long endTime1 = System.currentTimeMillis();
                    System.out.println("耗时1: " + (endTime1 - startTime1) + "ms");
                    long startTime2 = System.currentTimeMillis();
                    // 2. 获取或创建进度计数器
                    AtomicInteger counter = uploadProgress1.computeIfAbsent(
                            chunk.getFileId(),
                            k -> new AtomicInteger(0)
                    );
                    long endTime2 = System.currentTimeMillis();
                    System.out.println("耗时2: " + (endTime2 - startTime2) + "ms");
                    long startTime3 = System.currentTimeMillis();
                    // 3. 解码并保存分块
                    byte[] data = Base64Utils.decodeFromString(chunk.getChunkData());
                    saveChunk(chunk.getFileId(), chunk.getChunkNumber(), data);
                    long endTime3 = System.currentTimeMillis();
                    System.out.println("耗时3: " + (endTime3 - startTime3) + "ms");
                    long startTime4 = System.currentTimeMillis();

                    // 4. 检查是否完成
                    if (counter.incrementAndGet() == chunk.getTotalChunks()) {
                        String filePath = mergeChunks(chunk.getFileId(), chunk.getFileName(), chunk.getTotalChunks());
                        return AjaxResult.success();
                    }
                    long endTime4 = System.currentTimeMillis();
                    System.out.println("耗时4: " + (endTime4 - startTime4) + "ms");
                    return AjaxResult.success();

                } catch (Exception e) {
                    return AjaxResult.error("分块处理失败: " + e.getMessage());
                }
            }, executor);
        }

        private void saveChunk(String fileId, int chunkNum, byte[] data) throws IOException {
            Path dir = Paths.get("uploads", fileId);
            Files.createDirectories(dir);
            Files.write(dir.resolve("chunk_" + chunkNum), data);
        }

        private String mergeChunks(String fileId, String fileName, int totalChunks) throws IOException {
            Path output = Paths.get("uploads", fileName);
            try (java.io.OutputStream out = Files.newOutputStream(output)) {
                for (int i = 1; i <= totalChunks; i++) {
                    Files.copy(Paths.get("uploads", fileId, "chunk_" + i), out);
                }
            }
            // 清理临时文件
            FileSystemUtils.deleteRecursively(Paths.get("uploads", fileId));
            uploadProgress1.remove(fileId);
            return output.toString();

    }
}
